package globalCode;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;

//Rather intense/large class used to analyze and store information about the connections between every member in a single group

public class GroupConnections {
	
	ArrayList<Integer> userIDs; //List of all users (ids) in the group
	SortedSet<UserConnection> allCons; //Set of all combinations of users (pairs)
	private int groupID; //The specific group id being analyzed, passed as a paramater
	Connection sqlCon; //The connection to the sql server, passed as a parameter
	int[][] rankings; //After analysis, the ordered list of all pairs by score
	Object[][] fullRankings; //The full data of rankings after analaysis, including each individual subfact of the score
	int splitConsIndex = 0; //The current index of the user list being analyzed, used when the analysis is split (for threading)... should be reworked?
	
	public GroupConnections(int gID, Connection c){	
		sqlCon = c;
		setGroupID(gID);
	}
	
	//Runs all necessary commands to calculate the data concerning each user pair 
	public void calc(){
		userIDs = getIDs();
		allCons = getCons();
		rankings = getRankings();
	}
	
	//Retrieves the list of userID pairs and stores it in the userIDs field
	public void calcUserIDs(){
		userIDs = getIDs();
	}
	
	//returns a list of the pairs of users, stored as UserConnections -- this is the most time consuming part, esp. for large groups.
	public SortedSet<UserConnection> getCons(){
		//If this object has already done this calculation, return that result (performance thing)
		if(allCons != null)
			return allCons;
		
		//Initialization of the storage variable
		SortedSet<UserConnection> cons = new TreeSet<UserConnection>();
		
		for(int i = 0; i<userIDs.size()-1; i++){ //For every user but the last one
			for(int j = i+1; j<userIDs.size(); j++){ //For every user ID greater in the list than i
				UserConnection uc = new UserConnection(userIDs.get(i), userIDs.get(j), sqlCon);
				cons.add(uc);
			}
		}
		return cons;
	}
	
	//A split version of the connection analysis, used in threads
	public int splitGetCons(ConnThread ct){
		//Initialized the allCons storage variable if it doesn't exist.
		if(allCons==null)
			allCons = new TreeSet<UserConnection>();
		
		//Populates the userIDs list if it doesn't yet exist
		if(userIDs == null)
			userIDs = getIDs();
		
		//Recalls the current index to be analyzed
		int i = splitConsIndex;
		for(int j = i+1; j<userIDs.size(); j++){
			if(!ct.isStopped()){//Double checks to be sure it shouldn't stop
				//Runs the userconnection calculation and adds it the the allCons set
				UserConnection uc = new UserConnection(userIDs.get(i), userIDs.get(j), sqlCon);
				allCons.add(uc);
			}
		}
		
		if(i<userIDs.size()-2) //If the index isn't the second to last, return the current index
			return ++splitConsIndex;
		else //If it is, return -1 signaling that the process is done
			return -1;
	}
	
	//Retrieve the list of UserIDs present in the group
	public ArrayList<Integer> getIDs(){
		//Returns previously calculated data if present
		if(userIDs != null)
			return userIDs;
		
		//Initializes the variables to store the ids and to control the SQL connection
		ArrayList<Integer> ids = new ArrayList<Integer>();
		ResultSet rs = null;
		Statement stmt = null;


		try {
			stmt = sqlCon.createStatement();
			stmt.executeQuery("USE inetwork");
			rs = stmt.executeQuery("SELECT member FROM group_member WHERE `group`="+getGroupID()+";"); //Select each member of this group
			rs.last();
			int end = rs.getRow();
			rs.beforeFirst();
			
			//Runs through the returned result set, adding each ID to the arraylist
			for(int i = 0; i< end; i++){
				rs.next();
				ids.add(rs.getInt(1));
			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ids;
	}

	//Populates a list of the individual pair data, sorted by connection score
	public int[][] calcRankings() {
		
		//If the connections list doesn't exist, populate it
		if(allCons==null)
			allCons = getCons();
		
		//Creates and fills the ranking array
		int[][] ranks = new int[allCons.size()][3];
		int i = 0;
		for(UserConnection uc: allCons){
			ranks[i][0] = uc.id1;
			ranks[i][1] = uc.id2;
			ranks[i][2] = uc.value();
			i++;
		}
		return ranks;
	}
	
	//Returns the rankings array, creating it if necessary
	public int[][] getRankings(){
		if(rankings==null)
			rankings = calcRankings();
		return rankings;
	}
	
	//Returns the full rankings array, creating it if necessary
	public Object[][] getFullRankings(){
		if(fullRankings==null)
			fullRankings = calcFullRankings();
		return fullRankings;
	}
	
	//Returns the full list of the user connection info
	private Object[][] calcFullRankings() {
		if(allCons==null)
			allCons = getCons();
		Object[][] ranks = new Object[allCons.size()][8];
		int i=0;
		for(UserConnection uc: allCons){
			ranks[i] = uc.toInfoArray();
			i++;
		}
		return ranks;
	}

	//Returns a strong containing the basic rankings info from the ten highest scoring pairs
	public String topTenString(){
		String s = "";
		for(int i = 0; i<10; i++){
			if(i==rankings.length)
				return s;
			s+= rankings[i][0]+":"+rankings[i][1]+"   "+rankings[i][2]+"\n";
		}
		return s;
	}

	//Returns the ID of the group being analyzed
	public int getGroupID() {
		return groupID;
	}

	//Sets the ID of the group being analyzed -- should not be changed partway through.
	public void setGroupID(int groupID) {
		this.groupID = groupID;
	}
}
